/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

package util

import (
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"encoding/pem"
	"os"

	"github.com/pkg/errors"
	"golang.org/x/crypto/pbkdf2"
)

// EncryptPassword 对用户输入的原始密码进行加密，使用pbkdf2算法加密，iter是加密迭代次数，keylen是生成salt的长度
func EncryptPassword(origin string, iter, keylen int) (salt, encryptedPassword string, err error) {
	saltByte := make([]byte, keylen)
	_, err = rand.Read(saltByte)
	if err != nil {
		return "", "", errors.New("Encrypt error " + err.Error())
	}
	dk := pbkdf2.Key([]byte(origin), saltByte, iter, keylen, sha256.New)
	encryptedPassword = hex.EncodeToString(dk)
	return hex.EncodeToString(saltByte), encryptedPassword, nil
}

// EncryptWithSalt  根据原始密码和salt来生成加密后的密码
func EncryptWithSalt(origin, salt string, iter, keylen int) (encryptedPassword string, err error) {
	saltByte, err := hex.DecodeString(salt)
	if err != nil {
		return "", errors.New("EncryptWithSalt error " + err.Error())
	}
	dk := pbkdf2.Key([]byte(origin), saltByte, iter, keylen, sha256.New)
	encryptedPassword = hex.EncodeToString(dk)
	return encryptedPassword, nil
}

// DecryptWithRSA 解码使用base64编码的密文
func DecryptWithRSA(encryptStr, privatekeyPath string) (string, error) {
	encryptText, err := base64.StdEncoding.DecodeString(encryptStr)
	if err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	privateFile, err := os.Open(privatekeyPath)
	if err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	defer privateFile.Close()
	fileContext, err := privateFile.Stat()
	if err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	buffer := make([]byte, fileContext.Size())
	if _, err = privateFile.Read(buffer); err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	block, _ := pem.Decode(buffer)
	privatekey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	decryptText, err := rsa.DecryptPKCS1v15(rand.Reader, privatekey, encryptText)
	if err != nil {
		return "", errors.New("DecryptWithRSA err " + err.Error())
	}
	return string(decryptText), nil
}
